package org.ricks.net;

import org.ricks.net.handler.MessageProcessor;
import org.ricks.net.handler.NetMonitor;
import org.ricks.net.handler.Protocol;
import org.ricks.net.transport.KcpChannel;
import org.ricks.net.transport.UdpAioSession;
import org.ricks.net.transport.UdpBootstrap;
import org.ricks.net.transport.UdpChannel;
import org.ricks.utils.ByteUtils;

import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.DatagramChannel;

/**
 * @author chenwei
 * @date 2022/8/3016:24
 */
public class KcpServer extends UdpBootstrap {

    public KcpServer() {

    }

    public <Request> KcpServer(Protocol<Request> protocol) {
        super(protocol);
    }

    public <T> KcpServer(Protocol<T> protocol, MessageProcessor<T> messageProcessor) {
        super(protocol,messageProcessor);
        config.setKcp(true);
    }

    public void setListener(Listener netListener) {
        config.setNetListener(netListener);
    }

    @Override
    public void receiveHandle(UdpAioSession udpAioSession, ByteBuffer data) {
        KcpSeesion seesion = (KcpSeesion) udpAioSession;
        Kcp kcp = seesion.getKcp();
        try {
            input(kcp,data);
            kcp.update(System.currentTimeMillis());
            while (kcp.canRecv()) {
                int len = kcp.peekSize();
                ByteBuffer bb = ByteBuffer.allocate(len);
                 int n = kcp.recv(bb);
                if(n > 0) {
                    bb.flip();
                    super.receiveHandle(udpAioSession,bb); //kcp 包的字节流，这个时候应该是解析完后的KCP包，抛却了kcp 24字节消息头
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void input(Kcp kcp,ByteBuffer data) throws IOException {
        int ret = kcp.input(data);
        switch (ret) {
            case -1:
                throw new IOException("No enough bytes of head");
            case -2:
                throw new IOException("No enough bytes of data");
            case -3:
                throw new IOException("Mismatch cmd");
            case -4:
                throw new IOException("Conv inconsistency ");
            default:
                break;
        }
    }

    public void readHandle(UdpAioSession session,ByteBuffer buffer, byte[] bytes) {
        int conv = ByteBuffer.wrap(ByteUtils.slice(bytes,0,4)).order(ByteOrder.LITTLE_ENDIAN).getInt();
        KcpSeesion kcpSeesion = (KcpSeesion) session;
        kcpSeesion.getKcp().setConv(conv);
        super.readHandle(session,buffer,bytes);
    }

    public UdpChannel initChannel(DatagramChannel channel) {
        return createKcpChannel(channel);
    }

}
